#include <cstdlib>

#include "migrator.h"

#include "common/config/config.h"
#include "common/log/log.h"

#include "migrations/m0000001.h"

namespace Database
{

Migrator::Migrator(const std::string& databaseFilename)
    : m_database(new sqlite::database(databaseFilename.empty() ? CONFIG.database.file : databaseFilename))
{
    m_migrations.push_back(std::make_shared<M0000001>());
}

int Migrator::run()
{
    const unsigned currentVersion = currentDatabaseVersion();
    try
    {
        for (auto migration : m_migrations)
        {
            const unsigned migrationVersion = migration->version();
            if (currentVersion < migrationVersion)
            {
                LOG_INFO
                    << "Начат этап обновления версии БД: "
                    << currentVersion << " -> " << migrationVersion;
                migration->up(*m_database);
                setDatabaseVersion(migrationVersion);
                LOG_INFO
                    << "Этап обновления БД выполнен. Версия БД: "
                    << migrationVersion;
            }
        }
    }
    catch (const sqlite::sqlite_exception& exception)
    {
        LOG_ERROR
            << "Ошибка обновления версии БД: " << exception.what()
            << ", " << exception.get_sql();
        return EXIT_FAILURE;
    }

    LOG_INFO
        << "База данных полностью обновлена. Версия БД: "
        << currentDatabaseVersion();

    return EXIT_SUCCESS;
}

unsigned Migrator::currentDatabaseVersion() const
{
    unsigned result = 0;
    try
    {
        *m_database << "SELECT value FROM DatabaseVersion" >> result;
    }
    catch (const sqlite::sqlite_exception& exception)
    {
        LOG_WARN
            << "Ошибка получения версии БД: " << exception.what()
            << ", " << exception.get_sql();
        return 0;
    }
    return result;
}

void Migrator::setDatabaseVersion(unsigned version)
{
    *m_database << "CREATE TABLE IF NOT EXISTS DatabaseVersion (value int)";
    *m_database << "DELETE FROM DatabaseVersion";
    *m_database << "INSERT INTO DatabaseVersion (value) values (?);" << version;
}

} // namespace Database
